package dev.mrchen.flows.tool.runtime;

import dev.mrchen.flows.core.Executor;
import dev.mrchen.flows.core.FlowData;
import dev.mrchen.flows.core.FlowInfo;
import dev.mrchen.flows.core.util.IoUtil;

import java.io.*;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.OpenOption;
import java.nio.file.Path;

public class WriteFileRuntimeExecutor implements Executor {

    private final Path targetFile;

    private final WriteContent writeContent;

    private final OpenOption[] openOptions;

    public WriteFileRuntimeExecutor(Path targetFile, WriteContent writeContent , OpenOption... openOptions) {
        this.targetFile = targetFile;
        this.writeContent = writeContent;
        this.openOptions = openOptions;
    }


    @Override
    public void execute(FlowInfo nextFlow, FlowData data) throws Exception {
        Files.createDirectories(targetFile.getParent());
        try (OutputStream out =  Files.newOutputStream(targetFile, openOptions ) ) {
            try ( InputStream in = writeContent.getInputStream() ) {
                IoUtil.copy(in,out);
            }
        } finally {
            IoUtil.closeIo(writeContent);
        }
        nextFlow.next(data);
    }

    public interface WriteContent extends Closeable {

        InputStream getInputStream() throws Exception;

    }

    public static class StringContent implements WriteContent {

        private final String str;

        private final Charset charset;

        public StringContent(String str, Charset charset) {
            this.str = str;
            this.charset = charset;
        }

        @Override
        public InputStream getInputStream() {
            return new ByteArrayInputStream( str.getBytes(charset) );
        }

        @Override
        public void close() throws IOException {
            //
        }
    }


    public static class FileContent implements WriteContent {

        private final File file;

        public FileContent(File file) {
            this.file = file;
        }

        @Override
        public InputStream getInputStream() throws Exception {
            return Files.newInputStream(file.toPath());
        }

        @Override
        public void close() throws IOException {

        }
    }

    public static class ByteArrayContent implements WriteContent {

        private final byte[] bytes;

        public ByteArrayContent(byte[] bytes) {
            this.bytes = bytes;
        }

        @Override
        public InputStream getInputStream() throws Exception {
            return new ByteArrayInputStream(bytes);
        }

        @Override
        public void close() throws IOException {

        }
    }

}
